home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
Dots & Pixels
/
sources
/
screenarea.cp
< prev
next >
Wrap
Text File
|
1995-09-29
|
8KB
|
339 lines
#define min( a, b) (((a) < (b)) ? (a) : (b))
#define max( a, b) (((a) > (b)) ? (a) : (b))
#include <QuickDraw.h>
#include "C_randomizer.h"
#include "screenarea.h"
//
// 941027: significantly increase 'max_error' to 'pseudo-fix' the bug
// with Set/Move/EraseMultiDots. This costs us about 40K extra memory
// per instance of 'screenarea', but what the heck… Alternatively we
// could just allocate one common 'waste_area'.
//
// const int screenarea::max_error = 20;
//
const int screenarea::max_error = 20000;
screenarea::screenarea( int numbits, screen_position where)
: size( 1 << numbits)
, half_size( 1 << (numbits - 1))
, shiftbits( 2 * numbits - 9)
, coord_shift( 16 - numbits)
{
GDHandle thescreendevice = GetMainDevice();
const PixMapHandle pix_of_current = (**thescreendevice).gdPMap;
const Rect screenrect = (**pix_of_current).bounds;
const int half_screenHeight = (screenrect.bottom - screenrect.top) / 2;
const int half_screenWidth = (screenrect.right - screenrect.left) / 2;
int ypos = half_screenHeight - half_size;
int xpos = 0;
switch( where)
{
case centered:
xpos = half_screenWidth - half_size;
break;
case left_side:
xpos = half_screenWidth - (size + 48);
break;
case right_side:
xpos = half_screenWidth + 48;
break;
default:
DebugStr( "\pInvalid position in 'live_flow' constructor");
}
init( xpos, ypos);
}
screenarea::~screenarea()
{
screen -= half_size;
delete screen;
waste_area -= max_error;
delete waste_area;
}
void screenarea::fill( const int value)
{
for( int y = -half_size; y < half_size; y++)
{
unsigned char *row = screen[ y] - half_size;
for( int x = 0; x < size; x++)
{
*row++ = value;
}
}
}
void screenarea::add_circular_mask( void)
{
//
// We assume colors 0 through 127 to form a nice ramp from white
// to black and all other colors to be black. That way color 0
// is white and color 255 is black (as is customary on the Mac)
// _and_ we can make a perfectly black screen which turns into a
// grayscale image by adding 0x80 to the pixels.
//
// Note: we use (x+1) * (x+1) = x2 + 2 * x + 1 to speed things up
//
int y_squared = -half_size * -half_size;
const int square_limit = half_size * half_size;
for( int y = -half_size; y < half_size; y++)
{
unsigned char *row = screen[ y];
int square_sum = y_squared + -half_size * -half_size;
for( int x = -half_size; x < half_size; x++)
{
if( square_sum >= square_limit)
{
row[ x] = 255; // always stays black
} else {
row[ x] = (unsigned char)(0x80 + (square_sum >> shiftbits));
}
square_sum += (x << 1) + 1;
}
y_squared += (y << 1) + 1;
}
}
void screenarea::add_rectangular_mask( int mask_size)
{
const int mask_limit = half_size - mask_size;
//
// We assume colors 0 through 127 to form a nice ramp from white
// to black and all other colors to be black. That way color 0
// is white and color 255 is black (as is customary on the Mac)
// _and_ we can make a perfectly black screen which turns into a
// grayscale image by adding 0x80 to the pixels. => write 255
// to pixels which must stay black at all times, write 128 to
// pixels which may turn white.
//
for( int y = -half_size; y < half_size; y++)
{
unsigned char *row = screen[ y];
const int y_at_outside = (y < -mask_limit) || (y >= mask_limit);
if( y_at_outside)
{
for( int x = -half_size; x < half_size; x++)
{
row[ x] = 255;
}
} else {
for( int x = -half_size; x < half_size; x++)
{
const int x_at_outside = (x < -mask_limit) || (x >= mask_limit);
if( x_at_outside)
{
row[ x] = 255; // always stays black
} else {
row[ x] = 128;
}
}
}
}
}
void screenarea::add_fixation_dot( const int disparity)
{
add_big_dot( 0, 0, disparity);
}
void screenarea::add_stereo_cues( const int disparity)
{
const int one_q_size = half_size / 2;
add_big_dot( one_q_size, one_q_size, disparity);
add_big_dot( one_q_size, -one_q_size, disparity);
add_big_dot( -one_q_size, one_q_size, disparity);
add_big_dot( -one_q_size, -one_q_size, disparity);
}
void screenarea::compass2offsets( const char *compass, int *offsets, int *maxnum)
{
const int bovengrens = 500;
int *temp_result = new int[ bovengrens]; // more than enough?
int curoffset = 0;
int min_offset = 0;
int max_offset = 0;
int curindex = 0;
int numtoset = 0;
int stepoffset = 0;
int mark_them = false;
int index = 0;
while( compass[ index] != 0)
{
switch( compass[ index])
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
numtoset *= 10;
numtoset += compass[ index] - '0';
break;
case 'E':
mark_them = true;
case 'e':
stepoffset = 1;
break;
case 'S':
mark_them = true;
case 's':
stepoffset = rowBytes;
break;
case 'W':
mark_them = true;
case 'w':
stepoffset = -1;
break;
case 'N':
mark_them = true;
case 'n':
stepoffset = -rowBytes;
break;
case '.':
numtoset = 1; // replace '3.' by '.' ('3.' doesn't make sense)
mark_them = true;
break;
default:
DebugStr( "\pInvalid character in 'compasses' string");
}
if( (stepoffset != 0) || (mark_them == true))
{
if( numtoset == 0)
{
numtoset = 1;
}
if( mark_them)
{
mark_them = false;
for( int i = 0; i < numtoset; i++)
{
min_offset = min( curoffset, min_offset);
max_offset = max( curoffset, max_offset);
temp_result[ curindex] = curoffset;
curindex += 1;
curoffset += stepoffset;
}
} else {
curoffset += numtoset * stepoffset;
}
numtoset = 0;
stepoffset = 0;
}
index += 1;
}
//
// We now have computed both the actual number of offsets (in curindex),
// the actual offsets (in temp_result[ 0] through temp_result[ curindex - 1]),
// and the range of offsets encountered (in min_offset and max_offset, provided
// that zero is actually inside the range of offsets encountered).
//
if( min_offset <= -max_error)
{
DebugStr( "\pscreenarea::compass2offsets : minimal offset too small");
}
if( max_offset >= max_error)
{
DebugStr( "\pscreenarea::compass2offsets : maximal offset too large");
}
if( offsets != 0)
{
const int numtocopy = (*maxnum < curindex) ? *maxnum : curindex;
for( int i = 0; i < numtocopy; i++)
{
offsets[ i] = temp_result[ i];
}
}
*maxnum = curindex;
delete temp_result;
}
void screenarea::init( int xpos, int ypos)
{
screen = new unsigned char *[ size];
waste_area = new unsigned char[ size + 2 * max_error];
waste_area += max_error;
GDHandle thescreendevice = GetMainDevice();
const PixMapHandle pix_of_current = (**thescreendevice).gdPMap;
const Rect screenrect = (**pix_of_current).bounds;
rowBytes = ((**pix_of_current).rowBytes) & 0x1FFF;
const int screenHeight = screenrect.bottom - screenrect.top;
const int screenWidth = screenrect.right - screenrect.left;
unsigned char *screenBits = (unsigned char *)(**pix_of_current).baseAddr;
//
// safety
//
if( xpos + size >= screenWidth)
{
xpos = screenWidth - size;
}
if( xpos < 0)
{
xpos = 0;
}
for( int i = 0; i < size; i++)
{
const int ypos_plus_i = ypos + i;
if( (ypos_plus_i < 0) || (ypos_plus_i >= screenHeight))
{
screen[ i] = waste_area;
} else {
screen[ i] = screenBits + (ypos_plus_i * rowBytes) + xpos;
}
}
//
// We have now allocated the array to point at the start of the rows.
// Change this to point halfway into the rows:
//
#ifdef __MWERKS__
for( int i = 0; i < size; i++)
#else
for( i = 0; i < size; i++)
#endif
{
screen[ i] += half_size;
}
screen += half_size;
}
void screenarea::add_big_dot( const int x, const int y, const int disparity)
{
const int left_disparity = disparity / 2;
const int right_disparity = left_disparity - disparity;
unsigned char *screen_y = screen[ y];
screen_y[ x + left_disparity ] -= 1;
screen_y[ x + right_disparity ] -= 8;
screen_y[ x + left_disparity + 1] -= 1;
screen_y[ x + right_disparity + 1] -= 8;
screen_y = screen[ y + 1];
screen_y[ x + left_disparity ] -= 1;
screen_y[ x + right_disparity ] -= 8;
screen_y[ x + left_disparity + 1] -= 1;
screen_y[ x + right_disparity + 1] -= 8;
}